home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac-Source 1994 July
/
Mac-Source_July_1994.iso
/
C and C++
/
Libraries
/
TurboTCP 1.0.1
/
TurboTCP.source
/
CTCPDriver.cp
< prev
next >
Wrap
Text File
|
1993-12-10
|
11KB
|
484 lines
/*
** CTCPDriver.cp
**
** TurboTCP support library
** TCP driver interface class
**
** Copyright © 1993, FrostByte Design / Eric Scouten
**
*/
#define CTCPDriverNoGlobal // don’t redefine global vars
#include "CTCPDriver.h"
#ifndef TurboTCPHeaders
#include <CApplication.h>
#include <CBartender.h>
#include <GetMyIPAddr.h>
#include <cast.h>
#endif
#include <CDLOGDirector.h>
#include "CTCPApplication.h"
#include "CTCPAsyncCall.h"
#include "CTCPStream.h"
#include "CTCPResolverCall.h"
// resource definitions
#define DLOG_TCPDelayedQuit 23010
// define global reference to the TCP driver object
extern CApplication *gApplication;
extern CBartender *gBartender;
CTCPDriver *gTCPDriver; // not a class variable since it’s used
// so frequently throughout the application
// —— contruction/destruction ——
/*______________________________________________________________________
**
** ITCPDriver
**
** Clear the TCP driver object. Check to see if MacTCP is open. Optionally, opens TCP
** resolver.
**
** doOpenResolver (Boolean): TRUE to open TCP resolver as well
**
*/
void CTCPDriver::ITCPDriver (Boolean doOpenResolver)
{
// driver object must be locked, since it may be accessed during interupts
MoveHHi((Handle) this);
this->Lock(TRUE);
// clear variables
hasMacTCP = FALSE;
hasResolver = FALSE;
myTCPRefNum = 0;
myIPAddress = 0L;
gTCPDriver = this;
activeStreamList = NULL;
activeResolverList = NULL;
// clear asynch processing queue
asyncQueue.qFlags = 0;
asyncQueue.qHead = NULL;
asyncQueue.qTail = NULL;
// create the active TCP/DNR call lists
activeStreamList = new (CCluster);
activeStreamList->ICluster();
activeResolverList = new (CCluster);
activeResolverList->ICluster();
// see if TCP & DNR are available
CheckTCPDriver();
if (doOpenResolver)
CheckResolver();
}
/*______________________________________________________________________
**
** Dispose
**
** Dispose of this object and any lingering TCP async call objects or TCP stream objects.
** It is CRITICAL that any lingering TCP streams be closed, released, and disposed;
** otherwise MacTCP is *guaranteed* to crash the machine when the next app launches.
** If the resolver is open, wait until all resolver queries have been cancelled.
**
** If at least one second elapses between the start of this routine and the end, flash a
** dialog box to indicate the reason for the delay.
**
*/
void CTCPDriver::Dispose (void)
{
register long i;
CTCPStream *theStream;
unsigned long startTickCount;
unsigned long theTime;
CDLOGDirector *theDialog = NULL;
// cancel outstanding DNR calls & close resolver
if (hasResolver)
CTCPResolverCall::CloseResolver();
// kill any lingering streams
if (activeStreamList) {
for (i = 0; i < activeStreamList->numItems; i++) {
theStream = (CTCPStream*) (*(activeStreamList->items))[i];
theStream->PostponeDispose();
}
}
// wait for TCP to be done with everything
GetDateTime(&startTickCount);
gBartender->DisableMenuBar(); // disable all menus
while (!activeStreamList->IsEmpty()) {
// do a private event loop & toss up a dialog if it takes more than 2 seconds
GetDateTime(&theTime);
if ((theDialog == NULL) && (theTime - startTickCount >= 2)) {
theDialog = new (CDLOGDirector);
theDialog->IDLOGDirector(DLOG_TCPDelayedQuit, gApplication);
theDialog->BeginDialog();
}
// wait for TCP completions & terminations
gApplication->Process1Event();
}
// get rid of dialog box (if there was one)
ForgetObject(theDialog);
// dispose all the objects
ForgetObject(activeStreamList);
ForgetObject(activeResolverList);
CObject::Dispose();
}
// —— event handling ——
/*______________________________________________________________________
**
** ProcessNetEvents
**
** Respond to all delayed TCP notifications, completions, disposals. This routine should be
** hooked into the application’s event loop or some very frequently called routine.
**
*/
void CTCPDriver::ProcessNetEvents (void)
{
CObject *theAsyncObject;
TurboTCPQElemPtr theAsyncEntry;
CTCPAsyncCall *theAsyncCall;
CTCPResolverCall *theResolverCall;
CTCPStream *theStream;
// respond to all the events in the TCP asynchronous events queue, if there are any
while (asyncQueue.qHead) {
// figure out what object caused the notification
theAsyncEntry = (TurboTCPQElemPtr) asyncQueue.qHead;
theAsyncObject = theAsyncEntry->qSelfLink;
// remove it from the queue (just in case the event processing fails)
Dequeue((QElemPtr) theAsyncEntry, &asyncQueue);
// process the event
switch (theAsyncEntry->qType) {
case asyncCall:
theAsyncCall = CheckedCast(theAsyncObject, CTCPAsyncCall);
if (theAsyncCall)
theAsyncCall ->ProcessCompletion();
break;
case resolverCall:
theResolverCall = CheckedCast(theAsyncObject, CTCPResolverCall);
if (theResolverCall)
theResolverCall->ProcessNotify();
break;
case notifyStream:
theStream = CheckedCast(theAsyncObject, CTCPStream);
if (theStream)
theStream->ProcessNotify();
break;
case disposeStream:
theStream = CheckedCast(theAsyncObject, CTCPStream);
if (theStream)
theStream->Dispose();
break;
} // switch
} // while
}
// —— ensure that TCP/DNR are present ——
/*______________________________________________________________________
**
** CheckTCPDriver
**
** Check to see if the MacTCP driver is present. Should be done before opening each new
** connection (built into CTCPStream). If TCP driver is present, updates the current IP address.
**
** return (Boolean): TRUE if MacTCP driver is present
**
*/
Boolean CTCPDriver::CheckTCPDriver (void)
{
ParamBlockRec theParamBlock;
unsigned char theName[6] = "\p.IPP"; // MacTCP driver name
// if TCP not already confirmed, look for it
if (!hasMacTCP) {
theParamBlock.ioParam.ioNamePtr = (StringPtr) &theName;
theParamBlock.ioParam.ioPermssn = fsCurPerm;
if ((short) PBOpenSync(&theParamBlock) == 0) {
myTCPRefNum = theParamBlock.ioParam.ioRefNum;
hasMacTCP = TRUE;
}
}
/*
** If TCP driver available, get the IP address. This is done *each* time a new stream
** is created because the address might have changed. (This could happen on a machine
** connected by modem & SLIP, if the user hangs up the modem and re-dials the
** SLIP server without quitting the program.)
*/
FetchIPAddr();
return (hasMacTCP);
}
/*______________________________________________________________________
**
** CheckResolver
**
** Check to see if the MacTCP DNR code segment is available. If it isn’t, use the OpenResolver
** call to make it available.
**
** return (Boolean): TRUE if TCP resovler is present
**
*/
Boolean CTCPDriver::CheckResolver (void)
{
TRY {
CTCPResolverCall::OpenResolver();
hasResolver = TRUE;
}
CATCH {
hasResolver = FALSE;
NO_PROPAGATE;
}
ENDTRY;
return (hasResolver);
}
// —— get TCP driver numbers ——
/*______________________________________________________________________
**
** GetTCPRefNum
**
** Returns the Device Manager reference number for MacTCP, if available. Fails with
** “noTCPError” error if not available.
**
** return (short): MacTCP driver refnum
**
*/
short CTCPDriver::GetTCPRefNum (void)
{
if (!hasMacTCP)
FailOSErr(noTCPError);
return (myTCPRefNum);
}
/*______________________________________________________________________
**
** GetIPAddr
**
** Returns the current local IP address, if available. Fails with “noTCPError” error if
** MacTCP is not installed.
**
** return (ip_addr): current IP address
**
*/
ip_addr CTCPDriver::GetIPAddr (void)
{
if (!hasMacTCP)
FailOSErr(noTCPError);
return (myIPAddress);
}
/*______________________________________________________________________
**
** FetchIPAddr (protected method)
**
** Retrieve the local host’s IP address. Does nothing if MacTCP is not available. Stores the
** new address in the local field myIPAddress, which can be retrieved with the
** GetIPAddr() method.
**
*/
void CTCPDriver::FetchIPAddr (void)
{
struct GetAddrParamBlock theIPParamBlock;
myIPAddress = 0L;
if (hasMacTCP) {
theIPParamBlock.csCode = ipctlGetAddr;
theIPParamBlock.ioCRefNum = myTCPRefNum;
PBControlSync((ParmBlkPtr) &theIPParamBlock);
if (theIPParamBlock.ioResult == noErr)
myIPAddress = theIPParamBlock.ourAddress;
}
}
// —— postpone processing of interrupt-level notification ——
/*______________________________________________________________________
**
** RegisterActiveStream
**
** Add a TCP stream to the list of active TCP streams. The driver object uses this information
** to ensure that all streams are closed and terminated before the application quits.
**
** theStream (CTCPStream *): the stream to register
**
*/
void CTCPDriver::RegisterActiveStream (CTCPStream *theStream)
{
activeStreamList->Add(theStream);
}
/*______________________________________________________________________
**
** RegisterActiveResolver
**
** Add a DNR resolver call to the list of active TCP streams. The driver object uses this
** information to ensure that all resolver calls are closed and terminated before the
** application quits.
**
** theResolver (CTCPResolverCall *): the resolver call to register
**
*/
void CTCPDriver::RegisterActiveResolver (CTCPResolverCall *theResolver)
{
if (CheckResolverLimit()) // disallow 9th DNR call
FailOSErr(resolverBusy);
activeResolverList->Add(theResolver);
}
/*______________________________________________________________________
**
** RemoveActiveStream
**
** Remove a TCP stream from the list of active TCP streams. This message indicates that
** MacTCP is no longer dependent on the memory structure for the stream.
**
** theStream (CTCPStream *): the stream to register
**
*/
void CTCPDriver::RemoveActiveStream (CTCPStream *theStream)
{
if (activeStreamList) // just in case this is called during shutdown
activeStreamList->Remove(theStream);
}
/*______________________________________________________________________
**
** RemoveActiveResolver
**
** Remove a DNR resolver call from the list of active calls. This message indicates that
** the MacTCP DNR is no longer dependent on the memory structure for the call.
**
** theResolver (CTCPResolverCall *): the resolver call to register
**
*/
void CTCPDriver::RemoveActiveResolver (CTCPResolverCall *theResolver)
{
if (activeResolverList) // just in case this is called during shutdown
activeResolverList->Remove(theResolver);
}
/*______________________________________________________________________
**
** CheckResolverLimit
**
** Test to see if the DNR is at its capacity for active calls (currently 8).
**
** return (Boolean): TRUE if no more DNR calls may be issued now
**
*/
Boolean CTCPDriver::CheckResolverLimit (void)
{
return ((activeResolverList->numItems) >= maxResolverCalls);
}